package ml;

import java.util.ArrayList;

public class LabelMaker {
	private int m_time_interval;
	private double m_min_profit;
	private double m_max_loss;

	public LabelMaker(int time_interval, double min_profit, double max_loss) {
		m_time_interval = time_interval;
		m_min_profit = min_profit;
		m_max_loss = max_loss;
	}

	public ArrayList<Boolean> calculate(ArrayList<Double> data, int begin, int label_num, boolean cal_drop) {
		if ((label_num + begin) > data.size()) {
			return null;
		}

		ArrayList<Boolean> result = new ArrayList<Boolean>(label_num);

		// MinMaxIndexAndValue min_max = new MinMaxIndexAndValue(begin - 1,
		// begin - 1, 0, 0);

		double threshold = 0.5;
		if (cal_drop) {
			threshold = -0.5;
		}

		int end = begin + label_num;
		double current_data = 0;
		for (int i = begin; i < end; ++i) {
			current_data = data.get(i);

			// if ((min_max.index_min < i) || (min_max.index_max < i)) {
			// // need completely calculating
			// min_max = DataUtil.FindMinMax(data, i, i + m_time_interval);
			// } else {
			// // can be accelerated
			// if (current_data < min_max.min) {
			// min_max.min = current_data;
			// min_max.index_min = i;
			// }
			// if (current_data > min_max.max) {
			// min_max.max = current_data;
			// min_max.index_max = i;
			// }
			// }
			//
			// int label = calculateLabel(current_data, min_max.min,
			// min_max.max);

			int label = calculateLabel2(current_data, data, i, m_time_interval);

			if (label < threshold) {
				result.add(cal_drop);
			} else {
				result.add(!cal_drop);
			}
		}

		return result;
	}

	private int calculateLabel2(double current_data, ArrayList<Double> data, int start, int num) {
		int ret = 0;

		double max_rise = 0.0;
		double max_drop = 0.0;
		int total_num = Math.min(data.size(), start+num);
		for (int i = start + 1; i < total_num; i++) {
			double temp = data.get(i) - current_data;
			if (temp > max_rise) {
				max_rise = temp;
				if ((max_rise > m_min_profit) && (max_drop < m_max_loss)) {
					ret = 1;
					break;
				}
			} else if (temp < -max_drop) {
				max_drop = -temp;
				if ((max_drop > m_min_profit) && (max_rise < m_max_loss)) {
					ret = -1;
					break;
				}
			}
		}

		return ret;
	}

	// private int calculateLabel(double current, double min, double max) {
	// int ret = 0;
	//
	// if ((max - current) > m_min_profit) {
	// if ((current - min) < m_max_loss) {
	// // a large rise
	// ret = 1;
	// }
	// } else if ((current - min) > m_min_profit) {
	// if ((max - current) < m_max_loss) {
	// // a large drop
	// ret = -1;
	// }
	// }
	//
	// return ret;
	// }
}
